#ifndef RunArray_First
#define RunArray_First
#ifdef __GNUG__
#pragma interface
#endif

#include "Object.h"

class RunArrayIter;

//---- RunArray ----------------------------------------------------------------

enum RArrayGrowDir { eRARight, eRALeft };

class RunArray: public Object {
friend RunArrayIter;
	Object **cont;          // array with objects of runs
	int *runs;         // array with length of runs
	int size;               // size of allocated memory
	int count;              // number of runs
	int length;             // length of runarray

	//---- cache
	int theRun;             // the current run
	int runOffset;          // offset of the current run

	void OutOfRangeError(char *where, int at);
protected:
	void MoveTo(int);
	void Shift(int, int);
	void InsertRuns(int, int, Object**, int*, int);
	void CopyRuns(Object**, int*, int, int, int);
	int EndOfRun();
	bool IsInRun(int at);
	void NextRun();
	void PrevRun();

public:
	MetaDef(RunArray);

	//---- creation, destruction
	RunArray(int elements= 16);
	~RunArray();
	void FreeAll();

	void Insert(Object *op, int from, int to, int len);
	void ChangeRunSize(int i, int shift, RArrayGrowDir gd);
	void ReplaceRange(int from, int to, RunArray *src, int sfrom, int sto);

	void Paste(RunArray *paste, int from, int to);
	void Copy(RunArray *save, int from, int to);
	RunArray *Save(int from, int to);
	void Cut(int from, int to);

	Object *&operator[](int i);
	Object *RunAt(int i, int *start, int *end, int *size , int *lenat);
	int LengthAt(int i);
	int RunSizeAt(int i);
	int NumberOfRuns();
	int Size();
	void CheckInvariant();

	//---- standard overriden methods
	OStream &PrintOn(OStream&);
	IStream &ReadFrom(IStream&);
	void InspectorId(char *buf, int sz);
};

//---- RunArrayIter ------------------------------------------------------------

class RunArrayIter {
public:
	RunArrayIter(RunArray *s);
	Object *operator()();
	Object *Run(int *start, int *end, int *size);
		// iterate by runs
	Object **RunPtr(int *start, int *end, int *size);
		// iterate by runs and return address of run

private:
	RunArray *cs;
	int ce;         // index of runelement
	int ci;         // index of runarray
	int cp;
};

//---- inlines -----------------------------------------------------------------

inline int RunArray::EndOfRun()
	{ return theRun < count ? runOffset + runs[theRun] : length; }

inline bool RunArray::IsInRun(int at)
	{ return theRun < count ? at >= runOffset && at < EndOfRun() : at == length; }

inline void RunArray::NextRun()
	{ runOffset += runs[theRun++]; }

inline void RunArray::PrevRun()
	{ runOffset -= runs[--theRun]; }

inline int RunArray::NumberOfRuns()
	{ return count; }

inline int RunArray::Size()
	{ return length; }

#endif

